'use strict';

const path = require('path')
const semver = require('semver')
const userHome = require('user-home')
const commander = require('commander')
const pathExists = require('path-exists').sync
const colors = require('colors/safe')
const pkg = require('../package.json')
const log = require('@tangmen-cli-dev/log')
const exec = require('@tangmen-cli-dev/exec')
const constant = require('./const')
const program = new commander.Command()
let args

async function core() {
    try {
        await prepare()
        registerCommand()
    } catch (e) {
        log.error(e.message)
        if (program.debug) {
            console.log(e)
        }
    }
}

// 检查版本号
function checkPkgVersion() {
    log.info('当前脚手架版本号是： ', pkg.version)
}

// 检查node版本
function checkNodeVersion() {
    const currentVersion = process.version
    const lowestVersion = constant.LOWET_NODE_VERSION
    if (!semver.gte(currentVersion, lowestVersion)) {
        throw new Error(colors.red(`tangmen-cli 需要安装${lowestVersion}版本及以上的Node.js`))
    }
}

// 检查root启动
function checkRoot() {
    const rootCheck = require('root-check')
    rootCheck()
}

// 检查用户主目录
function checkUserHome() {
    if (!userHome || !pathExists(userHome)) {
        throw new Error(colors.red(`当前用户主目录不存在！`))
    }
}

// 检查环境变量
function checkEnv() {
    const dotenv = require('dotenv')
    const dotenvPath = path.resolve(userHome, '.env')
    if (pathExists(dotenvPath)) {
        dotenv.config({
            path: dotenvPath
        })
    }
    createDefaultConfig()
}

// 创建默认的环境变量配置
function createDefaultConfig() {
    // 创建一个cliConfig对象
    const cliConfig = {
        home: userHome
    }
    if (process.env.CLI_HOME) {
        cliConfig['cliHome'] = path.join(userHome, process.env.CLI_HOME)
    } else {
        cliConfig['cliHome'] = path.join(userHome, constant.DEFAULT_CLI_HOME)
    }
    // 直接将cliConfig对象的值挂载到process.env上 这样就可以在其他模块中轻松的拿到了
    process.env.CLI_HOME_PATH = cliConfig.cliHome
}

// 检查当前版本是否为最新版本
async function checkGlobalUpdate() {
    // 拿到当前的版本号
    const currentVersion = pkg.version
    // 拿到当前包的名字
    const npmName = pkg.name
    const {getNpmSemverVersion} = require('@tangmen-cli-dev/get-npm-info')
    // 经过一系列的操作获取最新版本号(从npm官方获取，过滤掉比当前版本号高的，再对数组进行排序)
    const latestVersion = await getNpmSemverVersion(currentVersion, npmName)
    // 拿最新版本号和当前版本号进行对比(semver是一个对比版本号的好工具)
    if (latestVersion && semver.gt(latestVersion, currentVersion)) {
        log.warn(colors.yellow(`请手动更新${npmName}, 当前版本:${currentVersion}, 最新版本: ${latestVersion}
                  更新命令: npm install -g ${npmName}
        `))
    }
}

// 准备阶段
async function prepare() {
    // 检查包的版本号
    checkPkgVersion()
    // 检查root启动
    checkRoot()
    // 检查用户主目录
    checkUserHome()
    // 检查环境变量
    checkEnv()
    // 检查cli是否最新版本
    await checkGlobalUpdate()
}

// 脚手架命令注册
function registerCommand() {
    // 初始化脚手架（name, version usage等）
    program
        .name(Object.keys(pkg.bin)[0])
        .version(pkg.version)
        .usage('<command> [options]')
        .option('-d, --debug', '是否开启调试模式', false)
        .option('-tp, --targetPath <targetPath>', '是否指定本地调试文件路径', '');

    // 注册一个init命令
    program
        .command('init [projectName]')
        .option('-f, --force', '是否强制初始化项目')
        // 将action中的操作解耦出来，事关commands的操作都放在commands目录结构下，一个操作一个文件夹
        // 本地开发的时候通过file: your-module-path 这种形式进行引进，等上线的时候lerna会自己转换成线上路径
        .action(exec)

    // 开启debug模式以后的监听
    program.on('option:debug', function () {
        if (program.debug) {
            process.env.LOG_LEVEL = 'verbose'
        } else {
            process.env.LOG_LEVEL = 'info'
        }
        log.level = process.env.LOG_LEVEL
    })

    // 指定targetPath
    program.on('option:targetPath', function () {
        // 保存到process.env对象上 可以在其他模块中拿到
        process.env.CLI_TARGET_PATH = program.targetPath
    })

    // 监听任何除已有command之外的命令 对未知命令的监听
    program.on('command:*', function (obj) {
        const availableCommands = program.commands.map((cmd) => cmd.name())
        console.log(colors.red('未知的命令: ' + obj[0]))
        if (availableCommands.length > 0) {
            console.log(colors.red('可用的命令: ' + availableCommands.join(',')))
        }
    })

    // 解析参数
    program.parse(process.argv)

    // 如果用户没有输入参数，那么可以给用户弹出来帮助面板 让他了解我们的脚手架如何使用
    if (program.args && program.args.length < 1) {
        program.outputHelp()
        console.log()
    }

}

module.exports = core;
